home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0190_Collection Classes for DELPHI 2.0.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-11-29  |  9.4 KB  |  321 lines

  1. unit Collect;
  2. { Collection classes for Delphi 2.0
  3.   Alin Flaider, 1996
  4.   aflaidar@datalog.ro }
  5.   
  6. interface
  7. uses Windows, Classes, Sysutils;
  8.  
  9. const
  10.   coIndexError = -1;              { Index out of range }
  11.   coOverflow   = -2;              { Overflow }
  12.   coUnderflow  = -3;              { Underflow }
  13.  
  14. type
  15.  CollException = class(Exception);
  16.  
  17.  TCollection = class( TObject)
  18.     private                       { return item at index position }
  19.        function    At( Index : integer) : Pointer;
  20.                                   { replace item at index position}
  21.        procedure   AtPut( Index : integer; Item : Pointer);
  22.     protected
  23.        It     : PPointerList;     { array of pointers }
  24.        Limit  : integer;          { Current Allocated size of array}
  25.        Delta  : integer;          {Number of items by which the collection grows when full}
  26.                                   { deletes item at index position }
  27.        procedure   AtDelete      (Index : integer);
  28.                                   { generates CollException }
  29.        procedure   Error         (Code,Info : Integer); virtual;
  30.                                   { destroys specified Item; override this method if Item is not
  31.                                     a descendant of TObject }
  32.        procedure   FreeItem      (Item : Pointer); virtual;
  33.     public
  34.        Count  : integer;          {Current Number of Items}
  35.        constructor create(aLimit, aDelta : integer);
  36.                                   {before deallocating object it disposes all items and the storage array}
  37.        destructor  destroy; override;
  38.                                   {inserts Item at specified position }
  39.        procedure   AtInsert( Index : integer; Item : Pointer);
  40.                                   {deletes and disposes Item at specified position}
  41.        procedure   AtFree(Index: Integer);
  42.                                   {deletes Item}
  43.        procedure   Delete( Item : Pointer);
  44.                                   {deletes all Items without disposing them }
  45.        procedure   DeleteAll;
  46.                                   {formerly Free, renamed to Clear to avoid bypassing inherited TObject.Free;
  47.                                    deletes and disposes Item }
  48.        procedure Clear(Item: Pointer);
  49.                                   {finds first item that satisfies condition specified in
  50.                                    function Test( Item: pointer): boolean}
  51.        function    FirstThat( Test : Pointer) : Pointer;
  52.                                   {finds last item that satisfies condition specified in
  53.                                    function Test( Item: pointer): boolean}
  54.        function    LastThat( Test : Pointer) : Pointer;
  55.                                   {calls procedure Action( Item: pointer) for each item in collection}
  56.        procedure   ForEach( Action : Pointer);
  57.                                   {disposes all items; set counter to zero}
  58.        procedure   FreeAll;
  59.                                   {finds position of Item using a linear search}
  60.        function    IndexOf( Item : Pointer) : integer; virtual;
  61.                                   {inserts Item at the end of collection}
  62.        procedure   Insert( Item : Pointer); virtual;
  63.                                   {packs collection by removing nil Items}
  64.        procedure   Pack;
  65.                                   {expands array of pointers }
  66.        procedure   SetLimit( aLimit : integer);virtual;
  67.                                   {direct access to items through position}
  68.        property Items[Index: integer]: pointer read At write AtPut; default;
  69.     end;
  70.  
  71.     TSortedCollection = class(TCollection)
  72.        Duplicates: boolean;       {if true, rejects item whose key already exists}
  73.                                   {override this method to specify relation bewtween two keys
  74.                                   1 if Key1 comes after Key2, -1 if Key1 comes before Key2,
  75.                                   0 if Key1 is equivalent to Key2}
  76.        function Compare (Key1,Key2 : Pointer): Integer; virtual; abstract;
  77.                                   {returns key of Item}
  78.        function KeyOf   (Item : Pointer): Pointer; virtual;
  79.                                   {finds index of item by calling Search}
  80.        function IndexOf (Item : Pointer): integer; virtual;
  81.                                   {finds item required position and performs insertion }
  82.        procedure Insert  (Item : Pointer); virtual;
  83.                                   {finds index of item by performing an optimised search}
  84.        function Search  (key : Pointer; Var Index : integer) : Boolean; virtual;
  85.     end;
  86.  
  87. implementation
  88.  
  89. constructor TCollection.Create(ALimit, ADelta: Integer);
  90. begin
  91.    inherited Create;
  92.    Limit:= 0;
  93.    Delta:=aDelta;
  94.    Count:=0;
  95.    It := nil;
  96.    SetLimit( ALimit);
  97. end;
  98.  
  99. destructor TCollection.Destroy;
  100. begin
  101.    FreeAll;
  102.    SetLimit(0);
  103.    inherited Destroy;
  104. end;
  105.  
  106. function TCollection.At(Index: Integer): Pointer;
  107. begin
  108.    If Index > pred(Count) then
  109.    begin
  110.      Error(coIndexError,0);
  111.      Result :=nil;
  112.    end
  113.    else Result := It^[Index];
  114. end;
  115.  
  116. procedure TCollection.AtPut(Index: Integer; Item: Pointer);
  117. begin
  118.    if (Index < 0) or (Index >= Count) then
  119.      Error(coIndexError,0)
  120.    else It^[Index] := Item;
  121. end;
  122.  
  123. procedure TCollection.AtDelete(Index: Integer);
  124. var p: pointer;
  125. begin
  126.    if (Index < 0) or (Index >= Count) then
  127.    begin
  128.       Error(coIndexError,0);
  129.       exit;
  130.    end;
  131.    if Index < pred(Count) then
  132.      move( It^[succ(Index)], It^[Index], (count-index)*sizeof(pointer));
  133.    Dec(Count);
  134. end;
  135.  
  136. procedure TCollection.AtInsert( Index: integer; Item: pointer);
  137. var i : integer;
  138. begin
  139.    if (Index < 0) or ( Index > Count) then
  140.    begin
  141.       Error(coIndexError,0);
  142.       exit;
  143.    end;
  144.    if Limit = Count then
  145.    begin
  146.      if Delta = 0 then
  147.      begin
  148.         Error(coOverFlow,0);
  149.         exit;
  150.      end;
  151.      SetLimit( Limit+Delta);
  152.    end;
  153.    If Index <> Count then  {move compensates for overlaps}
  154.       move( It^[Index], It^[Index+1], (count - index)*sizeof(pointer));
  155.    It^[Index] := Item;
  156.    Inc(Count);
  157. end;
  158.  
  159. procedure TCollection.Delete( Item: pointer);
  160. begin
  161.    AtDelete(Indexof(Item));
  162. end;
  163.  
  164. procedure TCollection.DeleteAll;
  165. begin
  166.    Count:=0
  167. end;
  168.  
  169. procedure TCollection.Error(Code, Info: Integer);
  170. begin
  171.    case Code of
  172.         coIndexError: raise CollException.Create('Collection error; wrong index: '+IntToStr(Info));
  173.         coOverflow:  raise CollException.Create('Collection overflow - cannot grow!');
  174.         coUnderflow: raise CollException.Create('Collection underflow - cannot shrink!');
  175.    end
  176. end;
  177.  
  178. function TCollection.FirstThat(Test: Pointer): Pointer;
  179. type
  180.    tTestFunc = function( p : pointer) : Boolean;
  181. var i : integer;
  182. begin
  183.   Result := nil;
  184.   for i := 0 to pred(count) do
  185.     if tTestFunc(test)(It^[i]) then begin
  186.        Result := It[i];
  187.        break
  188.     end
  189. end;
  190.  
  191. procedure TCollection.ForEach(Action: Pointer);
  192. type
  193.    tActionProc = procedure(p : pointer);
  194. var i : integer;
  195. begin
  196.   for i := 0 to pred(Count) do
  197.     tActionProc(Action)(It^[i]);
  198. end;
  199.  
  200. procedure TCollection.Clear(Item: Pointer);
  201. begin
  202.    Delete(Item);
  203.    FreeItem(Item);
  204. end;
  205.  
  206. procedure TCollection.FreeAll;
  207. var i : integer;
  208. begin
  209.   for I := 0 to Count - 1 do FreeItem(At(I));
  210.   Count := 0;
  211. end;
  212.  
  213. procedure TCollection.FreeItem(Item: Pointer);
  214. begin
  215.   if Item <> nil then TObject(Item).Free;
  216. end;
  217.  
  218. function TCollection.IndexOf(Item: Pointer): integer;
  219. var i : integer;
  220. begin
  221.   Result := -1;
  222.   for i := 0 to pred(count) do
  223.     if Item = It^[i] then begin
  224.        Result := i;
  225.        break
  226.     end
  227. end;
  228.  
  229. procedure TCollection.Insert(Item: Pointer);
  230. begin
  231.    AtInsert(Count,Item);
  232. end;
  233.  
  234. function TCollection.LastThat(Test: Pointer): pointer;
  235. type
  236.    tTestFunc = function( p : pointer) : Boolean;
  237. var i : integer;
  238. begin
  239.   Result := nil;
  240.   for i := pred(count) downto 1 do
  241.     if tTestFunc(test)(It^[i]) then begin
  242.        Result := It^[i];
  243.        break
  244.     end
  245. end;
  246.  
  247. procedure TCollection.Pack;
  248. var i: integer;
  249. begin
  250.   for i := pred(count) downto 0 do if It^[i] = nil then AtDelete(i);
  251. end;
  252.  
  253. procedure TCollection.SetLimit(ALimit: Integer);
  254. begin
  255.   if (ALimit < Count) then Error( coUnderFlow , 0);
  256.   if ALimit <> Limit then
  257.   begin
  258.     ReallocMem( It, ALimit* SizeOf(Pointer));
  259.     Limit := ALimit;
  260.   end;
  261. end;
  262.  
  263. function TSortedCollection.IndexOf(Item: Pointer): Integer;
  264. var
  265.   i: Integer;
  266. begin
  267.   IndexOf := -1;
  268.   if Search(KeyOf(Item), i) then
  269.   begin
  270.     if Duplicates then
  271.       while (i < Count) and (Item <> It^[I]) do Inc(i);
  272.     if i < Count then IndexOf := i;
  273.   end;
  274. end;
  275.  
  276. procedure TSortedCollection.Insert(Item: Pointer);
  277. var i : integer;
  278. begin
  279.   if not Search(KeyOf(Item), I) or Duplicates then AtInsert(I, Item);
  280. end;
  281.  
  282. function TSortedCollection.KeyOf(Item: Pointer): Pointer;
  283. begin
  284.   Result := Item;
  285. end;
  286.  
  287. function TSortedCollection.Search;
  288. var
  289.   L, H, I, C: Integer;
  290. begin
  291.   Search := False;
  292.   L := 0;
  293.   H := Count - 1;
  294.   while L <= H do
  295.   begin
  296.     I := (L + H) shr 1;
  297.     C := Compare(KeyOf(It^[I]), Key);
  298.     if C < 0 then L := I + 1 else
  299.     begin
  300.       H := I - 1;
  301.       if C = 0 then
  302.       begin
  303.         Search := True;
  304.         if not Duplicates then L := I;
  305.       end;
  306.     end;
  307.   end;
  308.   Index := L;
  309. end;
  310.  
  311. procedure TCollection.AtFree(Index: Integer);
  312. var
  313.   Item: Pointer;
  314. begin
  315.   Item := At(Index);
  316.   AtDelete(Index);
  317.   FreeItem(Item);
  318. end;
  319.  
  320. end.
  321.